// Berkeley Open Infrastructure for Network Computing
// http://boinc.berkeley.edu
// Copyright (C) 2005 University of California
//
// This is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation;
// either version 2.1 of the License, or (at your option) any later version.
//
// This software is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
// See the GNU Lesser General Public License for more details.
//
// To view the GNU Lesser General Public License visit
// http://www.gnu.org/copyleft/lesser.html
// or write to the Free Software Foundation, Inc.,
// 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

// A sample assimilator that only writes a log message.
//
//------------------- modifications - FZK BOINC project:
//
// This assimilator assumes the name of the workunit to be of the
// form: <name_masterid_rest> .
//
// When it finds a canonical resultid it will copy the canonical result files
// to the directory /home/boincadm/projects/poem/workspace/<username>/<masterid>/
// 
// It assumes the first first output file to be of the form wu_id.top and the second one
// of the form wu_id.out - the other output files are just copied without being renamed
//
// Here wu_id is the id given by the create_subjob program.
//
// To compile this program just checkout the current boinc sourcecode and overwrite the
// file sample_dummy_assimilator.C in the <source>/sched directory.
//

#include "config.h"
#include <cstdio>

#include <string.h>
#include <stddef.h>

#include "boinc_db.h"

#include "sched_msgs.h"
#include "sched_util.h"
#include "assimilate_handler.h"
#include "validate_util.h"
#include <iostream>

//for generic filesystem access (copy etc. should be implemented with boost later on)

#include <boost/filesystem/operations.hpp>

namespace fs = boost::filesystem;


using std::vector;
using std::string;

//assimilate handler is called whenever there is a finished workunit in the queuue
int
assimilate_handler(WORKUNIT & wu, vector < RESULT > & /*results */ ,
		   RESULT & canonical_result
    )
{
    fs::path const workspace_path("/home/boincadm/projects/poem/workspace/");


    SCOPE_MSG_LOG scope_messages(log_messages, SCHED_MSG_LOG::MSG_NORMAL);
    scope_messages.printf("[%s] Assimilating\n", wu.name);
    
    //Assimilating only takes place if a canonical result is present, otherwise an error message is written into the log
    if (wu.canonical_resultid) 
    {
	vector < string > output_file_names;

	scope_messages.printf("[%s] Found canonical result\n", wu.name);
	log_messages.printf_multiline(SCHED_MSG_LOG::MSG_DEBUG,
				      canonical_result.xml_doc_out,
				      "[%s] canonical result", wu.name);
//this stores the filenames of the returned output files in a vector<string>
	if (!(get_output_file_paths(canonical_result, output_file_names))) 
	{

//The following codelines cut the string into the relative tokens, username and jobname, to get the appropiate directory
//
	    char const delimiter = '_';	
            string const wu_name(wu.name); 
	    unsigned int first = wu_name.find(delimiter);
	    unsigned int second = wu_name.rfind(delimiter);
            second = wu_name.rfind(delimiter,second - 1 );
	    string const username = wu_name.substr(0,first);
	    string const jobname = wu_name.substr(first+1,second-first-1);

	    fs::path outpath = workspace_path / username / jobname / "incoming";
	
	    if (!fs::exists(outpath))
            {
	    	fs::create_directory(outpath);
		scope_messages.printf("Created directory %s\n",outpath.string().c_str());
            }

	    char cmd[1024];
	    int err = 0;
//Here the output files are copied into the just generated output directory. File numbers 0 and 1 are handled specifically
//and get the respective extensions .top and .out to be linked into the webfrontend correctly.
	    for (int i = 0; i < output_file_names.size(); ++i) {

		if (i > 1)	//i= 0 is always .top, i = 1 is always .out, i > 1 is unspecified
		{
		    snprintf(cmd, 1024, "mv %s %s",
			     output_file_names[i].c_str(),
			     outpath.string().c_str());
		}
		if (i == 0) {
		    snprintf(cmd, 1024, "mv %s %s/%d_out.xml.gz",
			     output_file_names[i].c_str(),
			     outpath.string().c_str(), wu.id);
		}
		if (i == 1) {
		    snprintf(cmd, 1024, "mv %s %s/%d_snap.xml.gz",
			     output_file_names[i].c_str(),
			     outpath.string().c_str(), wu.id);
		}
		if (i == 2) {
		    snprintf(cmd, 1024, "mv %s %s/%d_snap.pdb.gz",
			     output_file_names[i].c_str(),
			     outpath.string().c_str(), wu.id);
		}
		err = system(cmd);
		if (!err) {
		    scope_messages.printf
			("[%s] executed the system command %s\n", wu.name,
			 cmd);
		} else {
		    scope_messages.printf
			("[%s] executed the system command %s, Something went wrong\n",
			 wu.name, cmd);
		}

	    }
	}
    } else {
	scope_messages.printf("[%s] No canonical result\n", wu.name);
    }
    if (wu.error_mask & WU_ERROR_COULDNT_SEND_RESULT) {
	log_messages.printf(SCHED_MSG_LOG::MSG_CRITICAL,
			    "[%s] Error: couldn't send a result\n",
			    wu.name);
    }
    if (wu.error_mask & WU_ERROR_TOO_MANY_ERROR_RESULTS) {
	log_messages.printf(SCHED_MSG_LOG::MSG_CRITICAL,
			    "[%s] Error: too many error results\n",
			    wu.name);
    }
    if (wu.error_mask & WU_ERROR_TOO_MANY_TOTAL_RESULTS) {
	log_messages.printf(SCHED_MSG_LOG::MSG_CRITICAL,
			    "[%s] Error: too many total results\n",
			    wu.name);
    }
    if (wu.error_mask & WU_ERROR_TOO_MANY_SUCCESS_RESULTS) {
	log_messages.printf(SCHED_MSG_LOG::MSG_CRITICAL,
			    "[%s] Error: too many success results\n",
			    wu.name);
    }
    return 0;
}

const char *BOINC_RCSID_8f6a5a2d27 =
    "$Id: sample_dummy_assimilator.C,v 1.10 2005/11/21 18:34:34 korpela Exp $";
